#include "StdAfx.h"
#include "MaterialProjectFile.h"
#include "MaterialProject.h"
#include "MaterialTemplateGenerator.h"

namespace Lit
{
	namespace Editor
	{
		namespace Material
		{
			RecentProjectList::RecentProjectList(){ load(); }
			RecentProjectList::~RecentProjectList(){}
				
			bool RecentProjectList::load( ){
				Lit::FileStream strm( System::EditorPath()+"/" + MATERIAL_RECENTS_FILE, Stream::TextRead );
				if( !strm.valid() ) return false;
				while( !strm.eof() )
				{
					std::string ln = strm.readLine();
					Ogre::StringUtil::trim( ln );
					FilePath f(ln);
					if( f.exists() && !has(f) ) 
						d.push_back( ln );
				}
				return true;
			}
			bool RecentProjectList::save( ){
				Lit::FileStream strm( System::EditorPath()+"/"+MATERIAL_RECENTS_FILE, Stream::TextWrite );
				if( !strm.valid() ) return false;
				for( auto i=d.begin(); i!=d.end(); i++ )
				{
					if( !(*i).str().empty() && (*i).exists() )
						strm.write(i->str()+"\n");
				}
				return true;
			}

			bool RecentProjectList::has( const FilePath &path ) const
			{
				for( auto i=d.begin(); i!=d.end(); i++ )
				{
					if( (*i).str() == path.str() ) return true;
				}
				return false;
			}
			std::vector<FilePath>::iterator RecentProjectList::begin(){return d.begin();}
			std::vector<FilePath>::iterator RecentProjectList::end(){return d.end();}
				
			std::vector<FilePath>::const_iterator RecentProjectList::begin()const{return d.begin();}
			std::vector<FilePath>::const_iterator RecentProjectList::end() const{return d.end();}

			std::vector<FilePath>::iterator RecentProjectList::find( const FilePath &path )
			{
				for( auto i=d.begin(); i!=d.end(); i++ )
				{
					if( (*i).str() == path.str() ) return i;
				}
				return d.end();
			}
			std::vector<FilePath>::const_iterator RecentProjectList::find( const FilePath &path ) const
			{
				for( auto i=d.begin(); i!=d.end(); i++ )
				{
					if( (*i).str() == path.str() ) return i;
				}
				return d.end();
			}
			void RecentProjectList::add( const FilePath &path ){ 
				FilePath f(path);
				load();
				if( has(path) )
				{
					auto i=find(path);
					f = FilePath(*i);
					d.erase( i );
				}
				d.push_back(f);
				save();
			}
			
			bool RecentProjectList::empty() const{
				return d.empty();
			}
			
			void RecentProjectList::clear(){
				d.clear();
			}
			
			unsigned short RecentProjectList::size() const
			{
				return d.size();
			}

			FilePath RecentProjectList::lastProject( ) const
			{
				if( d.empty() ) return FilePath();
				return d.back();
			}

			std::vector<FilePath> RecentProjectList::lastProjects( const unsigned short upper_lim ) const
			{
				std::vector<FilePath> ret;
				unsigned short rmax = std::max( upper_lim, (unsigned short)d.size() );
				for( unsigned short i=0; i<rmax; i++ )
				{
					ret.push_back( FilePath(d[i]) );
				}
				return ret;
			}
			void ProjectItemCreator::browseDirectory()
			{
				QString p = QFileDialog::getExistingDirectory( this, "Choose Directory", ui.directory->text() );
				if( p.isEmpty() )
					return;
				ui.directory->setText( p );
			}
			void ProjectItemCreator::updateItemType(QTreeWidgetItem* itm, int c)
			{
				ui.listWidget->clear();
				QStringList ogreItems( QStringList() << "Material" << "Compositor" << "Particle" << "Program" );
				QStringList resItems( QStringList() << "Texture" );
				QStringList otherItems( QStringList() << "TextFile" );
				if( itm == mOgreNode )
				{
					ui.listWidget->addItems( ogreItems );
				}
				else if( itm == mResNode )
				{
					ui.listWidget->addItems( resItems );
				}
				else if( itm == mOtherNode )
				{
					ui.listWidget->addItems( otherItems );
				}
				else
				{
					ui.listWidget->addItems( ogreItems + resItems + otherItems );
				}
			}
			ProjectItemCreator::ProjectItemCreator ( QWidget * parent ) : QDialog(parent), mProject(NULL){
				ui.setupUi(this);
			}
			ProjectItemCreator::~ProjectItemCreator(){}

			void ProjectItemCreator::setupUi()
			{
				Qt::ItemFlags flags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
				ui.treeWidget->clear();
					
				mAllNode = new QTreeWidgetItem(ui.treeWidget, QStringList("All"));
				mOgreNode = new QTreeWidgetItem(mAllNode, QStringList("Ogre"));
				mResNode = new QTreeWidgetItem(mAllNode, QStringList("Resources"));
				mOtherNode = new QTreeWidgetItem(mAllNode, QStringList("Other"));
					
				mAllNode->setExpanded( true ); mAllNode->setFlags( flags );
				mOgreNode->setExpanded( true ); mOgreNode->setFlags( flags );
				mResNode->setExpanded( true ); mResNode->setFlags( flags );
				mOtherNode->setExpanded( true ); mOtherNode->setFlags( flags );
					
				mAllNode->setSelected(true);

				updateItemType(mAllNode, 0);
				if( mProject )
					ui.directory->setText( TO_QT(mProject->getProjectHome() + "\\") );
					
				connect( ui.browseDir, SIGNAL(clicked(bool)), this, SLOT(browseDirectory()) );
				connect( ui.treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(updateItemType(QTreeWidgetItem*, int)) );
			}
			ProjectFileDefinition ProjectItemCreator::define( const std::string &name, const std::string &extension, bool accepted_, const std::string &directory, const std::string &category, const std::string &content ) const
			{
				return ProjectFileDefinition( name, extension, accepted_, directory, category, content );
			}
			ProjectFileDefinition ProjectItemCreator::currentDefinition( bool accepted ) const
			{
				std::string category = ui.treeWidget->currentItem()?FROM_QT(ui.treeWidget->currentItem()->text(0)):"";
				category += (category.empty()?"":"/")+FROM_QT(ui.listWidget->currentItem()->text());
				std::string directory = FROM_QT(ui.directory->text());
				std::string name = FROM_QT(ui.name->text());
				std::string type = FROM_QT(ui.listWidget->currentItem()->text()); 
				Ogre::StringUtil::toLowerCase( type );

				return define( name, type, accepted, directory, category, "" );
			}
			std::vector<ProjectFileDefinition> ProjectItemCreator::exec( Project * proj )
			{
				mProject = proj;
				setupUi();
				
				std::vector<ProjectFileDefinition> vret;
				vret.push_back( ProjectFileDefinition() );
				ProjectFileDefinition & ret(vret[0]);

				int c=QDialog::Accepted;
				while( c==QDialog::Accepted )
				{
					c = QDialog::exec();
					ret = currentDefinition(false);
					if( c == QDialog::Rejected ) return vret;
					// accepted if has selection
					ret.accepted = true;
					if( !ui.listWidget->currentItem() )
					{
						ui.listWidget->setFocus();
						QMessageBox::information( this, "No selection", "Please choose an item type first !", QMessageBox::Ok );
					}
					// else tell to choose something
					else if( ui.name->text().isEmpty() ){
						ui.name->setFocus();
						QMessageBox::information( this, "No name", "Please choose an item name first !", QMessageBox::Ok );
					}
					else break;
					
				}

				ret = currentDefinition(ret.accepted);
				// add extensions here to define new override for template generator !
				if( ret.extension == "program" )
				{
					ProgramDef pret(CreateShaderDialog::createShader( this, ret.name ));
					if( pret.accepted )
					{
						std::vector<ProjectFileDefinition> vret2;
						vret2.push_back( define( pret.name, "program", pret.hasDefinition, FROM_QT(ui.directory->text()), currentDefinition().category, pret.generate() ) );
						vret2.push_back( define( pret.vertexShader.name, pret.vertexShader.language, pret.hasVertex, FROM_QT(ui.directory->text()), currentDefinition().category, pret.generateVertex() ) );
						vret2.push_back( define( pret.pixelShader.name, pret.pixelShader.language, pret.hasPixel, FROM_QT(ui.directory->text()), currentDefinition().category, pret.generatePixel() ) );
						return vret2;
					}
				}
				return vret;
			}

			ProjectFile::ProjectFile( const std::string &nam, Project * proj ) 
				: name(nam), project(proj)
			{
				item = new QTreeWidgetItem( QStringList() << TO_QT(FilePath(name).fileName()) << " " );
				proj->getRootNode()->addChild( item );
				window = new Window( nam, proj->getName(), proj->getMdiArea()  );
			}
			ProjectFile::~ProjectFile()
			{
				if( item ) delete item, item = NULL;
				if( window ) delete window, window = NULL;
			}
			std::string ProjectFile::getName() const{return FROM_QT(item?item->text(0):TO_QT(name));}
			void ProjectFile::setText( const std::string &text ){ getEditor()->setText(text); }
			std::string ProjectFile::getText() const{ return getEditor()->getText(); }

			bool ProjectFile::isModified() const{ return getEditor()->isModified(); }
			void ProjectFile::setModified( bool state ){ getEditor()->setModified(state); }

			void ProjectFile::save( const Lit::FilePath& base_dir )
			{
				std::ofstream strm( project->getFilePath( getName() ).str(), std::ios::out );
				strm << getText();
				strm.close();

				setModified( false );
			}
			void ProjectFile::load( const Lit::FilePath& base_dir )
			{
				FilePath dir(base_dir.str()+"/"+project->getName());
				FileSystem::createDirectories( dir.str() );
				FilePath path(dir.str()+"/"+getName());
				if( !path.exists() ) throw FileMissing(path.str(), EXC_LOC);
				std::ifstream strm( path.str(), std::ios::in );
				while( !strm.eof() )
				{
					std::string ln;
					std::getline( strm, ln );
					setText( ln );
				}
				setModified( false );
				strm.close();
			}
			TextEdit * ProjectFile::getCodeEditor(){ assert( window ); return window?window->getCodeEditor():NULL; }
			const TextEdit * ProjectFile::getCodeEditor() const{ assert( window ); return window?window->getCodeEditor():NULL; }

			EditorWidget * ProjectFile::getEditor(){ assert( window ); return window?window->getEditor():NULL; }
			const EditorWidget * ProjectFile::getEditor() const{ assert( window ); return window?window->getEditor():NULL; }

			const Window* ProjectFile::getWindow() const{ return window; }
			Window* ProjectFile::getWindow() { return window; }

			const QTreeWidgetItem* ProjectFile::getItem() const{ return item; }
			QTreeWidgetItem* ProjectFile::getItem() { return item; }

			const Project* ProjectFile::getProject() const{ return project; }
			Project* ProjectFile::getProject() { return project; }

		};
	};
};